Skip to content

Conversation

@philnik777
Copy link
Contributor

No description provided.

@github-actions
Copy link

⚠️ C/C++ code formatter, clang-format found issues in your code. ⚠️

You can test this locally with the following command:
git-clang-format --diff origin/main HEAD --extensions ,h -- libcxx/include/__algorithm/specialized_algorithms.h libcxx/include/__algorithm/fill_n.h libcxx/include/__bit_reference --diff_from_common_commit

⚠️
The reproduction instructions above might return results for more than one PR
in a stack if you are using a stacked PR workflow. You can limit the results by
changing origin/main to the base branch/commit you want to compare against.
⚠️

View the diff from clang-format here.
diff --git a/libcxx/include/__algorithm/specialized_algorithms.h b/libcxx/include/__algorithm/specialized_algorithms.h
index 532927468..56b59d724 100644
--- a/libcxx/include/__algorithm/specialized_algorithms.h
+++ b/libcxx/include/__algorithm/specialized_algorithms.h
@@ -19,7 +19,7 @@ _LIBCPP_BEGIN_NAMESPACE_STD
 
 // FIXME: This should really be an enum
 namespace _Algorithm {
-  struct __fill_n {};
+struct __fill_n {};
 } // namespace _Algorithm
 
 template <class>

@philnik777 philnik777 force-pushed the introduce_specialized_algorithms branch from 84a6b98 to da4198d Compare November 18, 2025 15:12
@philnik777 philnik777 marked this pull request as ready for review November 19, 2025 14:57
@philnik777 philnik777 requested a review from a team as a code owner November 19, 2025 14:57
@llvmbot llvmbot added the libc++ libc++ C++ Standard Library. Not GNU libstdc++. Not libc++abi. label Nov 19, 2025
@llvmbot
Copy link
Member

llvmbot commented Nov 19, 2025

@llvm/pr-subscribers-libcxx

Author: Nikolas Klauser (philnik777)

Changes

Full diff: https://github.com/llvm/llvm-project/pull/167295.diff

5 Files Affected:

  • (modified) libcxx/include/CMakeLists.txt (+1)
  • (modified) libcxx/include/__algorithm/fill_n.h (+17-40)
  • (added) libcxx/include/__algorithm/specialized_algorithms.h (+35)
  • (modified) libcxx/include/__bit_reference (+48-4)
  • (modified) libcxx/include/module.modulemap.in (+1)
diff --git a/libcxx/include/CMakeLists.txt b/libcxx/include/CMakeLists.txt
index 4b2713191c1c0..a7fbe4aadb16b 100644
--- a/libcxx/include/CMakeLists.txt
+++ b/libcxx/include/CMakeLists.txt
@@ -194,6 +194,7 @@ set(files
   __algorithm/simd_utils.h
   __algorithm/sort.h
   __algorithm/sort_heap.h
+  __algorithm/specialized_algorithms.h
   __algorithm/stable_partition.h
   __algorithm/stable_sort.h
   __algorithm/swap_ranges.h
diff --git a/libcxx/include/__algorithm/fill_n.h b/libcxx/include/__algorithm/fill_n.h
index 426fe228bdabb..3d06ea4f080fe 100644
--- a/libcxx/include/__algorithm/fill_n.h
+++ b/libcxx/include/__algorithm/fill_n.h
@@ -10,13 +10,13 @@
 #define _LIBCPP___ALGORITHM_FILL_N_H
 
 #include <__algorithm/for_each_n_segment.h>
-#include <__algorithm/min.h>
+#include <__algorithm/specialized_algorithms.h>
 #include <__config>
-#include <__fwd/bit_reference.h>
 #include <__iterator/iterator_traits.h>
 #include <__iterator/segmented_iterator.h>
-#include <__memory/pointer_traits.h>
+#include <__type_traits/enable_if.h>
 #include <__utility/convert_to_integral.h>
+#include <__utility/move.h>
 
 #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
 #  pragma GCC system_header
@@ -29,7 +29,12 @@ _LIBCPP_BEGIN_NAMESPACE_STD
 
 // fill_n isn't specialized for std::memset, because the compiler already optimizes the loop to a call to std::memset.
 
-template <class _OutputIterator, class _Size, class _Tp>
+template <
+    class _OutputIterator,
+    class _Size,
+    class _Tp,
+    __enable_if_t<!__specialized_algorithm<_Algorithm::__fill_n, __single_iterator<_OutputIterator> >::__has_algorithm,
+                  int> = 0>
 inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 _OutputIterator
 __fill_n(_OutputIterator __first, _Size __n, const _Tp& __value) {
 #ifndef _LIBCPP_CXX03_LANG
@@ -47,42 +52,14 @@ __fill_n(_OutputIterator __first, _Size __n, const _Tp& __value) {
   return __first;
 }
 
-template <bool _FillVal, class _Cp>
-_LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void
-__fill_n_bool(__bit_iterator<_Cp, false> __first, typename __size_difference_type_traits<_Cp>::size_type __n) {
-  using _It            = __bit_iterator<_Cp, false>;
-  using __storage_type = typename _It::__storage_type;
-
-  const int __bits_per_word = _It::__bits_per_word;
-  // do first partial word
-  if (__first.__ctz_ != 0) {
-    __storage_type __clz_f = static_cast<__storage_type>(__bits_per_word - __first.__ctz_);
-    __storage_type __dn    = std::min(__clz_f, __n);
-    std::__fill_masked_range(std::__to_address(__first.__seg_), __clz_f - __dn, __first.__ctz_, _FillVal);
-    __n -= __dn;
-    ++__first.__seg_;
-  }
-  // do middle whole words
-  __storage_type __nw = __n / __bits_per_word;
-  std::__fill_n(std::__to_address(__first.__seg_), __nw, _FillVal ? static_cast<__storage_type>(-1) : 0);
-  __n -= __nw * __bits_per_word;
-  // do last partial word
-  if (__n > 0) {
-    __first.__seg_ += __nw;
-    std::__fill_masked_range(std::__to_address(__first.__seg_), __bits_per_word - __n, 0u, _FillVal);
-  }
-}
-
-template <class _Cp, class _Size>
-inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 __bit_iterator<_Cp, false>
-__fill_n(__bit_iterator<_Cp, false> __first, _Size __n, const bool& __value) {
-  if (__n > 0) {
-    if (__value)
-      std::__fill_n_bool<true>(__first, __n);
-    else
-      std::__fill_n_bool<false>(__first, __n);
-  }
-  return __first + __n;
+template <class _OutIter,
+          class _Size,
+          class _Tp,
+          __enable_if_t<__specialized_algorithm<_Algorithm::__fill_n, __single_iterator<_OutIter> >::__has_algorithm,
+                        int> = 0>
+_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 _OutIter __fill_n(_OutIter __first, _Size __n, const _Tp& __value) {
+  return __specialized_algorithm<_Algorithm::__fill_n, __single_iterator<_OutIter> >()(
+      std::move(__first), __n, __value);
 }
 
 template <class _OutputIterator, class _Size, class _Tp>
diff --git a/libcxx/include/__algorithm/specialized_algorithms.h b/libcxx/include/__algorithm/specialized_algorithms.h
new file mode 100644
index 0000000000000..53292746839fb
--- /dev/null
+++ b/libcxx/include/__algorithm/specialized_algorithms.h
@@ -0,0 +1,35 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef _LIBCPP___ALGORITHM_SPECIALIZED_ALGORITHMS_H
+#define _LIBCPP___ALGORITHM_SPECIALIZED_ALGORITHMS_H
+
+#include <__config>
+
+#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
+#  pragma GCC system_header
+#endif
+
+_LIBCPP_BEGIN_NAMESPACE_STD
+
+// FIXME: This should really be an enum
+namespace _Algorithm {
+  struct __fill_n {};
+} // namespace _Algorithm
+
+template <class>
+struct __single_iterator;
+
+template <class _Alg, class... _Ranges>
+struct __specialized_algorithm {
+  static const bool __has_algorithm = false;
+};
+
+_LIBCPP_END_NAMESPACE_STD
+
+#endif // _LIBCPP___ALGORITHM_SPECIALIZED_ALGORITHMS_H
diff --git a/libcxx/include/__bit_reference b/libcxx/include/__bit_reference
index a3e6defd405f8..20e5bc7d5695b 100644
--- a/libcxx/include/__bit_reference
+++ b/libcxx/include/__bit_reference
@@ -15,8 +15,10 @@
 #include <__algorithm/copy_backward.h>
 #include <__algorithm/copy_n.h>
 #include <__algorithm/equal.h>
+#include <__algorithm/fill_n.h>
 #include <__algorithm/min.h>
 #include <__algorithm/rotate.h>
+#include <__algorithm/specialized_algorithms.h>
 #include <__algorithm/swap_ranges.h>
 #include <__assert>
 #include <__bit/countr.h>
@@ -467,10 +469,6 @@ private:
   template <class _Dp>
   friend struct __bit_array;
 
-  template <bool _FillVal, class _Dp>
-  _LIBCPP_CONSTEXPR_SINCE_CXX20 friend void
-  __fill_n_bool(__bit_iterator<_Dp, false> __first, typename __size_difference_type_traits<_Dp>::size_type __n);
-
   template <class _Dp, bool _IC>
   _LIBCPP_CONSTEXPR_SINCE_CXX20 friend __bit_iterator<_Dp, false> __copy_aligned(
       __bit_iterator<_Dp, _IC> __first, __bit_iterator<_Dp, _IC> __last, __bit_iterator<_Dp, false> __result);
@@ -537,6 +535,52 @@ private:
   template <bool _ToCount, class _Dp, bool _IC>
   friend typename __bit_iterator<_Dp, _IC>::difference_type _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20
   __count_bool(__bit_iterator<_Dp, _IC>, typename __size_difference_type_traits<_Dp>::size_type);
+
+  template <class, class...>
+  friend struct __specialized_algorithm;
+};
+
+template <class _Cp>
+struct __specialized_algorithm<_Algorithm::__fill_n, __single_iterator<__bit_iterator<_Cp, false> > > {
+  static const bool __has_algorithm = true;
+
+  template <bool _FillVal>
+  _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 static void
+  __impl(__bit_iterator<_Cp, false> __first, typename __size_difference_type_traits<_Cp>::size_type __n) {
+    using _It            = __bit_iterator<_Cp, false>;
+    using __storage_type = typename _It::__storage_type;
+
+    const int __bits_per_word = _It::__bits_per_word;
+    // do first partial word
+    if (__first.__ctz_ != 0) {
+      __storage_type __clz_f = static_cast<__storage_type>(__bits_per_word - __first.__ctz_);
+      __storage_type __dn    = std::min(__clz_f, __n);
+      std::__fill_masked_range(std::__to_address(__first.__seg_), __clz_f - __dn, __first.__ctz_, _FillVal);
+      __n -= __dn;
+      ++__first.__seg_;
+    }
+    // do middle whole words
+    __storage_type __nw = __n / __bits_per_word;
+    std::__fill_n(std::__to_address(__first.__seg_), __nw, _FillVal ? static_cast<__storage_type>(-1) : 0);
+    __n -= __nw * __bits_per_word;
+    // do last partial word
+    if (__n > 0) {
+      __first.__seg_ += __nw;
+      std::__fill_masked_range(std::__to_address(__first.__seg_), __bits_per_word - __n, 0u, _FillVal);
+    }
+  }
+
+  template <class _Size, class _Tp>
+  _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 static __bit_iterator<_Cp, false>
+  operator()(__bit_iterator<_Cp, false> __first, _Size __n, const _Tp& __value) {
+    if (__n > 0) {
+      if (__value)
+        __impl<true>(__first, __n);
+      else
+        __impl<false>(__first, __n);
+    }
+    return __first + __n;
+  }
 };
 
 _LIBCPP_END_NAMESPACE_STD
diff --git a/libcxx/include/module.modulemap.in b/libcxx/include/module.modulemap.in
index 57d66cd1ccaef..6858f6cedac54 100644
--- a/libcxx/include/module.modulemap.in
+++ b/libcxx/include/module.modulemap.in
@@ -829,6 +829,7 @@ module std [system] {
     module simd_utils                             { header "__algorithm/simd_utils.h" }
     module sort_heap                              { header "__algorithm/sort_heap.h" }
     module sort                                   { header "__algorithm/sort.h" }
+    module specialized_algorithms                 { header "__algorithm/specialized_algorithms.h" }
     module stable_partition                       { header "__algorithm/stable_partition.h" }
     module stable_sort {
       header "__algorithm/stable_sort.h"


_LIBCPP_BEGIN_NAMESPACE_STD

// FIXME: This should really be an enum
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since we can't use an enum due to C++03, I would remove the FIXME. We don't have a clear plan to refactor this in the short term.

struct __single_iterator;

template <class _Alg, class... _Ranges>
struct __specialized_algorithm {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This needs a comment explaining what this is all about.

In particular, please mention that _Ranges is an "arbitrary" subset of the arguments to the algorithm that is used for dispatching purposes.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

libc++ libc++ C++ Standard Library. Not GNU libstdc++. Not libc++abi.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants